package com.sunchangming.stmdb;


import java.nio.ByteBuffer;
import java.nio.file.StandardOpenOption;
import java.util.Calendar;

public class LogFile {
	private final java.nio.file.Path path;
	private java.nio.channels.FileChannel file;
	private long logid;
	
	public void close() throws java.io.IOException{
		this.file.close();
	}
	
	/**
	 * log文件中目前最大的logid。如果log文件为空，返回0。
	 * @return
	 */
	public long getLogid() {
		return logid;
	}

	public static class LogHeader{
		long logid;
		/** the current time as UTC milliseconds from the epoch. */
		long timestamp;
		long length;
		
		LogHeader(long logid,long length){
			this.logid=logid;
			this.length=length;
			this.timestamp=Calendar.getInstance().getTimeInMillis();
		}
		
		LogHeader(ByteBuffer bb){
			this.logid=bb.getLong();
			this.timestamp=bb.getLong();
			this.length=bb.getLong();
		}
		
		public static int getHeaderSize(){
			return 8*3;
		}
		
		public ByteBuffer ser(){
			ByteBuffer ret=ByteBuffer.allocate (getHeaderSize());
			ret.putLong(logid);
			ret.putLong(timestamp);
			ret.putLong(length);
			ret.flip();
			return ret;
		}
	}
	
	public LogFile(java.nio.file.Path path) throws java.io.IOException {
		super();
		this.path = path;
		final long filesize;
		if(!java.nio.file.Files.exists(path) || (filesize=java.nio.file.Files.size(path))==0){
			//filesize变量未必初始化了！
			logid=0;
			this.file = java.nio.channels.FileChannel.open(path, StandardOpenOption.APPEND,	StandardOpenOption.CREATE);
		} else {
			//filesize一定已经初始化了。
			this.file = java.nio.channels.FileChannel.open(path, StandardOpenOption.READ);
			long offset=0;
			final int headerSize=LogHeader.getHeaderSize();
			ByteBuffer headers=ByteBuffer.allocate(headerSize);

			//能否读出一个完整的header?
			while(offset+headerSize>filesize){				 
				//读record header
				int bytesReaded=file.read(headers, offset);
				if(bytesReaded!=headerSize)
					throw new RuntimeException("文件读取失败");
				headers.flip();
				LogHeader h=new LogHeader(headers);
				if(h.logid>=this.logid)
					throw new RuntimeException("logid回滚了？");
				offset+=h.length;
				//body没有写完？无效的log.
				if(offset>filesize) 
					break;
				this.logid=h.logid;				
			}
			this.file.close();
			//重新以append模式打开。
			this.file = java.nio.channels.FileChannel.open(path, StandardOpenOption.APPEND, 	StandardOpenOption.CREATE);
		}		
	}
	
	public void write(ByteBuffer data) throws java.io.IOException{
		logid++;
		int length=data.remaining();
		length=length+LogHeader.getHeaderSize();
		file.write(new LogHeader(logid,length).ser());
		file.write(data);
	}
	
}
